using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using System.Threading;

namespace Sunny.UI;

public class FileLogger : BaseLogger, IDisposable
{
	private int _savePeriod = 100;

	private bool _useCache;

	private readonly StringBuilder _builder;

	private readonly ConcurrentQueue<string> _queue;

	public string _fileNamePrefix;

	private Timer _timer;

	private bool _isWriting;

	private volatile bool _disposed;

	private int LastFileIndex = 1;

	private string LastFilePath = "";

	public string FilePath { get; }

	public int MaxFileSize { get; set; }

	public bool IsDisposed => _disposed;

	public FileLogger(int savePeriod = 100)
		: this("Log", savePeriod)
	{
	}

	public FileLogger(LogLevel level, int savePeriod = 100)
		: this("Log", string.Empty, level, savePeriod)
	{
	}

	public FileLogger(string name, int savePeriod = 100)
		: this(name, string.Empty, LogLevel.Info, savePeriod)
	{
	}

	public FileLogger(string name, LogLevel level, int savePeriod = 100)
		: this(name, string.Empty, level, savePeriod)
	{
	}

	public FileLogger(string name, string dir, LogLevel level = LogLevel.Info, int savePeriod = 100)
	{
		_builder = new StringBuilder();
		_queue = new ConcurrentQueue<string>();
		base.Level = level;
		MaxFileSize = 4000000;
		_fileNamePrefix = name;
		FilePath = Path.Combine(Dir.CurrentDir(), "Logs").DealPath();
		if (!dir.IsNullOrEmpty())
		{
			FilePath = Path.Combine(FilePath, dir).DealPath();
		}
		Dir.CreateDir(FilePath);
		StartThread(savePeriod);
	}

	private void StartThread(int period)
	{
		_useCache = period > 0;
		if (_useCache)
		{
			_savePeriod = period;
			_timer = new Timer(TimerCallback, null, 0, period);
		}
	}

	private void TimerCallback(object o)
	{
		if (IsDisposed || _timer == null || _isWriting)
		{
			return;
		}
		_isWriting = true;
		_builder.Clear();
		string text = "";
		string log = "";
		while (_queue.Count > 0)
		{
			if (_queue.TryDequeue(out var result))
			{
				if (text == "")
				{
					text = result.Left("yyyy-MM-dd".Length);
				}
				else if (result.Left("yyyy-MM-dd".Length) != text)
				{
					log = result;
					break;
				}
				_builder.AppendLine(result);
			}
		}
		string text2 = "";
		try
		{
			if (_builder.Length > 0)
			{
				text2 = GetLogFileName(text, "yyyy-MM-dd");
				StreamWriter streamWriter = new StreamWriter(text2, append: true, Encoding.UTF8);
				streamWriter.Write(_builder.ToString());
				streamWriter.Flush();
				streamWriter.Close();
				WriteAtOnce(log);
			}
		}
		catch (Exception ex)
		{
			Console.WriteLine("Write log error: " + text2 + ", " + ex.Message);
		}
		finally
		{
			_isWriting = false;
		}
	}

	public void ThrowIfDisposed()
	{
		if (IsDisposed)
		{
			throw new ObjectDisposedException(GetType().FullName);
		}
	}

	public void Dispose()
	{
		Dispose(disposing: true);
		GC.SuppressFinalize(this);
	}

	protected virtual void Dispose(bool disposing)
	{
		if (!IsDisposed)
		{
			if (disposing)
			{
				TimerCallback(null);
				_timer?.Change(-1, -1);
				_timer?.Dispose();
			}
			_disposed = true;
		}
	}

	private string GetLogFileName(string log, string format)
	{
		if (!log.StartsWith("20"))
		{
			return "";
		}
		DateTime dt = log.Left(format.Length).ToDateTime(format);
		string text = Path.Combine(FilePath, dt.YearMonthString(withLink: false)).DealPath();
		Dir.CreateDir(text);
		if (!text.Equals(LastFilePath))
		{
			LastFilePath = text;
			LastFileIndex = 1;
		}
		string text2 = text + dt.ToString("yyyyMMdd") + "." + LastFileIndex.ToString("D2") + "." + _fileNamePrefix + ".txt";
		FileInfo fileInfo = new FileInfo(text2);
		while (fileInfo.Exists && fileInfo.Length >= MaxFileSize)
		{
			LastFileIndex++;
			text2 = text + dt.ToString("yyyyMMdd") + "." + LastFileIndex.ToString("D2") + "." + _fileNamePrefix + ".txt";
			fileInfo = new FileInfo(text2);
		}
		return text2;
	}

	public override void WriteLog(string log)
	{
		if (_useCache)
		{
			_queue.Enqueue(log);
		}
		else
		{
			WriteAtOnce(log);
		}
	}

	private void WriteAtOnce(string log)
	{
		if (IsDisposed || log.IsNullOrEmpty())
		{
			return;
		}
		string text = "";
		try
		{
			text = GetLogFileName(log, "yyyy-MM-dd");
			StreamWriter streamWriter = File.AppendText(text);
			streamWriter.WriteLine(log);
			streamWriter.Flush();
			streamWriter.Dispose();
		}
		catch (Exception ex)
		{
			Console.WriteLine("Write log error: " + text + ", " + ex.Message);
		}
	}
}
